-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update simplified DnD handler api and memoize useDnDHooks #3533
Conversation
let {draggingCollectionRef, draggingKeys} = globalDndState; | ||
let isInternalDrop = draggingCollectionRef?.current != null && draggingCollectionRef?.current === ref?.current; | ||
let {draggingKeys} = globalDndState; | ||
let isInternal = isInternalDropOperation(ref); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bunch of these isInternal
checks use ref
instead of relying on the global state's dropCollectionRef
because I felt it was safer this way (global state is spooky in general). Since these are all within useDroppableCollection
, the ref should be equal to dropCollectionRef
for the most part (some exceptions exist where we want to calculate isInternal
before we even set dropCollectionRef
)
Build successful! 🎉 |
isInternalDrop -> isInternal. Use target provided to onDrop for the util handlers
d69cdbc
to
60993aa
Compare
Build successful! 🎉 |
…r Android slight optimization in DragManager by removing extraneous setDropCollectionRef in favor of drag end handling isInternal logic instead. Also fix detection of Android virtual clicks, element clicked via click() will have pointerType="" and detail=0 so we can rely on the previous detail=0 logic for that case instead
directory may be a type that is common among user data so it may accidentally conflict with our special directory keyword in acceptedDragTypes. To resolve this we change it so acceptedDragTypes allows a Symbol equivalent that we defined for directory
@@ -26,7 +26,6 @@ | |||
"@react-aria/utils": "^3.13.3", | |||
"@react-aria/visually-hidden": "^3.4.1", | |||
"@react-stately/dnd": "3.0.0-alpha.10", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was doing some auditing and have a clarifying question: should things like @react-stately/dnd
/@react-types/*
be in devDeps instead if they are only used to import types/interfaces? I was under the impression that we could do a import type
for things like that and thus avoid needing to include them within the dependencies because they only matter during dev (aka typechecking)
@@ -33,7 +33,7 @@ export function isVirtualClick(event: MouseEvent | PointerEvent): boolean { | |||
// Android TalkBack's detail value varies depending on the event listener providing the event so we have specific logic here instead | |||
// If pointerType is defined, event is from a click listener. For events from mousedown listener, detail === 0 is a sufficient check | |||
// to detect TalkBack virtual clicks. | |||
if (isAndroid() && (event as PointerEvent).pointerType != null) { | |||
if (isAndroid() && (event as PointerEvent).pointerType) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
click events triggered by .click()
will have a pointerType = ""
and detail === 0
so we can avoid this check and fallback to the detail === 0
check below
@@ -68,45 +68,46 @@ export interface DnDOptions extends Omit<DraggableCollectionProps, 'preview' | ' | |||
} | |||
|
|||
export function useDnDHooks(options: DnDOptions): DnDHooks { | |||
let { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This diff is really just me moving everything into a single useMemo
@@ -159,12 +161,12 @@ export class DragTypes implements IDragTypes { | |||
this.includesUnknownTypes = !hasFiles && dataTransfer.types.includes('Files'); | |||
} | |||
|
|||
has(type: string) { | |||
if (this.includesUnknownTypes || (type === 'directory' && this.types.has(GENERIC_TYPE))) { | |||
has(type: string | DirectorySymbolType) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does string | symbol
work here? Might be good to keep this a little more vague rather than only allowing directorySymbol
, in case we add more special symbol types in the future.
@@ -18,6 +18,8 @@ import {Key, RefObject} from 'react'; | |||
import {useId} from '@react-aria/utils'; | |||
|
|||
const droppableCollectionIds = new WeakMap<DroppableCollectionState, string>(); | |||
export const directorySymbol = Symbol(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We haven't really done something like this before, but do we want to use upper case for constants? I think that's a fairly common convention. Something like DIRECTORY_DRAG_TYPE
? If not, I still think naming it with drag type in the name rather than "symbol" makes sense.
...(isDraggable ? dragHooks : {}), | ||
...(isDroppable ? dropHooks : {}), | ||
...(isDraggable || isDroppable ? {isVirtualDragging} : {}) | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of creating the objects unconditionally and then merging them, you could assign properties from within an if statement? Maybe a little more efficient.
let hooks = {};
if (isDraggable) {
hooks.useDraggableCollectionState = /* ... */
}
// etc.
also expand acceptedDragTypes to accept any symbol in case we add more unique drag types in the future
also skips calling the util handlers if filteredItems is empty
this allows the user to define what drop operations a droppable collection accepts, making it so copy or link can become the new default operation.
@@ -70,9 +70,9 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state: | |||
let filteredItems = items; | |||
if (acceptedDragTypes) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this check isn't needed anymore? Or maybe it should be if (acceptedDragTypes !== 'all' || shouldAcceptItemDrop)
as an optimization?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yep, thanks for catching this
…eact-spectrum into dnd_api_simplification_followups
Build successful! 🎉 |
this avoids the need for adding a dev dep of react-spectrum/dnd to the types packages
@@ -21,7 +21,6 @@ import { | |||
SpectrumSelectionProps, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would love to delete the @react-types/list
package now that aria/spectrum define and export the types but a bit worried about if people are using it since it have been released.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it be weird to change this package to re-export the types from aria/spectrum instead? only for backward compatibility I guess. not sure how important tho
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
feels a bit weird to have the dependencies go the other way, but at least it wouldn't be circular since nothing else should depend on this types package. I'll go ahead and update
Build successful! 🎉 |
for backcompat. We define and export these props from aria/spectrum packages now, the react-types/list packages is no longer necessary since it is only used for one component
Build successful! 🎉 |
Build successful! 🎉 |
Followup review items from #3266
✅ Pull Request Checklist:
📝 Test Instructions:
🧢 Your Project:
RSP